package com.fitns.user.service.user;

import com.fitns.user.conf.ExcelConstants;
import com.fitns.user.constant.RedisKey;
import com.fitns.user.dao.baseConfig.TbPersonLederDao;
import com.fitns.user.dao.organ.OrganDao;
import com.fitns.user.dao.user.RoleDao;
import com.fitns.user.dao.user.UserDao;
import com.fitns.user.dao.user.UserRoleDao;
import com.fitns.user.dto.organ.OrganVO;
import com.fitns.user.dto.user.*;
import com.fitns.user.exception.*;
import com.fitns.user.model.baseConfig.TbPersonLedger;
import com.fitns.user.model.user.User;
import com.fitns.user.model.user.UserRole;
import com.fitns.user.service.organ.OrganService;
import com.fitns.user.utils.ContextUtils;
import com.fitns.user.utils.DeEnCode;
import com.fitns.user.utils.RedisUtil;
import com.github.pagehelper.PageInfo;
import com.xiaoleilu.hutool.crypto.SecureUtil;
import com.xiaoleilu.hutool.lang.Validator;
import com.xiaoleilu.hutool.util.CollectionUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by zhou on 2018/08/01
 */

@Service
@Slf4j
public class UserService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private TbPersonLederDao personLederDao;

    @Autowired
    private RoleService roleService;

    @Autowired
    private UserRoleDao userRoleDao;

    @Autowired
    private RoleDao roleDao;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private OrganService organService;

    @Autowired
    private PrivilegeService privilegeService;

    @Autowired
    private OrganDao organDao;


    @Transactional
    public UserVO insert(UserVO userVO) {
        if (Validator.isNull(userVO)) {
            throw ServiceException.create(UserMsgCode.USER_INSER_IS_NULL);
        }
        this.vaildateForAdd(userVO);
        //初始密码默认为123456
        userVO.setPassword("123456");
        userVO.setLoginNum(0);

        //查看人员台账中是否有对应用户，没有就新增
        TbPersonLedger personLedger = personLederDao.searchByTell(userVO.getTellNumber());
        if (Validator.isNull(personLedger)) {
            personLedger = new TbPersonLedger();
            personLedger.setPhone(userVO.getTellNumber());
            personLedger.setName(userVO.getUsername());
            personLedger.setInputTime(new Date());
            personLedger.setModifyTime(new Date());
            personLedger.setOrganId(userVO.getOrganId());
            personLederDao.insert(personLedger);

        } else {
            userVO.setTrueName(personLedger.getName());
            userVO.setOrganId(personLedger.getOrganId());
        }

        User user = this.add(userVO);
        //处理用户角色关系
        processUserRole(user, userVO.getRoleVOS());
        userVO.setId(user.getId());
        userVO.setPassword(user.getPassword());
        return userVO;
    }

    //验证用户名称和手机号码
    public void vaildateForAdd(UserVO userVO) {
        User user1 = userDao.findUserByTellOrName(DeEnCode.encode(userVO.getUsername()));
        User user2 = userDao.findUserByTellOrName(DeEnCode.encode(userVO.getTellNumber()));
        if (Validator.isNotNull(user1) || Validator.isNotNull(user2)) {
            throw ServiceException.create(UserMsgCode.USER_ALL_EXIST);
        }
    }

    public User add(UserVO userVO) {
        validateAdd(userVO);
        User user = new User();
        UserVO vo = new UserVO();
        vo=this.enCodeUser(userVO);
        BeanUtils.copyProperties(vo, user);
        user.setPassword(DeEnCode.encode(userVO.getPassword()));
        userDao.insert(user);
        userVO.setPassword(user.getPassword());
        userVO.setId(user.getId());
        return userVO;
    }

    public void validateAdd(UserVO userVO) {
        if (Validator.isNull(userVO)) {
            throw ServiceException.create(UserMsgCode.USER_INSER_IS_NULL);
        }
        if (Validator.isNull(userVO.getUsername()) || Validator.isNull(userVO.getTrueName()) || Validator.isNull(userVO.getTellNumber())) {
            throw ServiceException.create(UserMsgCode.USER_MESSEAGE_NOT);
        }
        if (Validator.isNull(userVO.getOrganId())) {
            throw ServiceException.create(UserMsgCode.USER_ORGAN_IS_NULL);
        }
        OrganVO organVO = new OrganVO();
        organVO.setId(userVO.getOrganId());
        if (Validator.isNull(organDao.findById(organVO.getId()))) {
            throw ServiceException.create(OrganMsgCode.ORGAN_NOT_EXIST);
        }

        if (Validator.isNull(userVO.getRoleVOS())) {
            throw ServiceException.create(UserMsgCode.USER_ROLE_IS_NULL);

        }

    }

    /**
     * 功能描述:处理用户角色关系
     *
     * @return:
     */
    @Transactional
    public void processUserRole(User user, List<RoleVO> roleVOS) {
        if (Validator.isNull(roleVOS)) {
            return;
        }
        Long currentUserId = this.currentUser().getId();

        //修改或添加后用户需要绑定的所有角色id
        Set<Long> currentRoleIds = roleVOS.parallelStream().map(RoleVO::getId).collect(Collectors.toSet());

        //验证角色的创建任是否与登录用户一致
        List<Long> currentRoleIdList = roleVOS.parallelStream().map(RoleVO::getId).collect(Collectors.toList());
        List<RoleVO> roleVOList = roleDao.selectBatchIds(currentRoleIdList);
        if (Validator.isNotNull(roleVOList)) {
            roleVOList.forEach(roleVO -> {
                if (!currentUserId.equals(roleVO.getCreateId())) {
                    log.error("角色" + roleVO.getName() + "非当前登录用户创建");
                    throw ServiceException.create(RoleMsgCode.ROLE_IS_NOT_CURRENT_USE_CREATE);
                }
            });
        }

        //查询用户当前绑定的角色ids
        List<UserRole> userRoles = new ArrayList<>();
        userRoles = this.findUserRoleByUserId(user.getId());
        Set<Long> alreadyRoleIds = userRoles.parallelStream().map(UserRole::getRoleId).collect(Collectors.toSet());

        //计算出需要删除的角色id
        Set<Long> removeIds = new HashSet<>(alreadyRoleIds);
        removeIds.removeAll(currentRoleIds);
        List<Long> removeList = userRoles.parallelStream().filter(userRole -> removeIds.contains(userRole.getRoleId()))
                .map(UserRole::getId).collect(Collectors.toList());


        //计算需要添加的角色id
        Set<Long> addIds = new HashSet<>(currentRoleIds);
        addIds.remove(alreadyRoleIds);

        //删除角色
        if (Validator.isNotNull(removeList) && removeList.size() != 0) {
            userRoleDao.deleteBatch(removeList);
        }

        //添加角色
        if (Validator.isNotNull(addIds) && addIds.size() != 0) {
            addIds.forEach(id -> {
                UserRole userRole = new UserRole();
                userRole.setUserId(user.getId());
                userRole.setRoleId(id);
                userRoleDao.insert(userRole);
            });
        }

    }

    public List<UserRole> findUserRoleByUserId(Long userId) {
        UserRole userRoleSearch = new UserRole();
        userRoleSearch.setUserId(userId);
        return userRoleDao.search(userRoleSearch);

    }

    public UserVO findDetailUser(Long useId) {
        UserVO userVO = userDao.searchOne(useId);
        List<RoleVO> roleVOS = roleDao.findByUserId(useId);
        OrganVO organVO = organDao.findParentById(userVO.getOrganId());
        String str = "";
        String[] organNames = organVO.getName().split(",");
        int len = organNames.length;
        for (int i = len - 1; i >= 0; i--) {
            str += organNames[i] + "-";
        }
        if (str != "") {
            str = str.substring(0, str.length() - 1);
        }
        userVO.setOrganName(str);
        userVO.setRoleVOS(roleVOS);
        return userVO;
    }

    /**
     * 获取当前登录用户
     *
     * @return UserVO
     */
    public UserVO currentUser() {

        String token = ContextUtils.getToken();
        if (Validator.isNull(redisUtil.get(RedisKey.USER_ID.of(token)))) {
            throw ServiceException.create(LoginMsgCode.USER_LOGIN_OUT);
        }
        Long userId = Long.parseLong(redisUtil.get(RedisKey.USER_ID.of(token)));
        if (Validator.isNull(userId)) {
            throw ServiceException.create(LoginMsgCode.USER_LOGIN_OUT);
        }
        UserVO userVO = redisUtil.get(RedisKey.USER.of(userId.toString()), UserVO.class);
        return deCodeUser(userVO);
    }

    /**
     * 功能描述:查询
     *
     * @param:
     * @return:
     */
    public PageInfo<UserVO> search(UserCondition userCondition) {
        userCondition.setOrganId(currentUser().getOrganId());
        List<UserVO> userVOList = userDao.search(userCondition);
        PageInfo<UserVO> pageInfo;
        List<UserVO> userVOS = new ArrayList<>();
        if (Validator.isNotNull(userVOList)) {
            userVOList.forEach(userVO -> {
                UserVO vo = this.deCodeUser(userVO);
                userVOS.add(vo);

            });
            pageInfo = new PageInfo<>(userVOS);
        } else {
            pageInfo = new PageInfo<>(userVOList);
        }
        return pageInfo;
    }


    public void resetPassword(Long id){
        if(Validator.isNull(id)){
            return;
        }
        UserVO userVO=userDao.searchOne(id);
        if(Validator.isNull(userVO)){
            throw ServiceException.create(UserMsgCode.USER_NOT_EXIST);
        }

        String password=DeEnCode.encode("123456");
        userVO.setPassword(password);
        userDao.update(userVO);
    }

    @Transactional
    public List<UserVO> importExcel(List<List<String>> excelList) {
        //TODO
        List<UserVO> dtoList = new ArrayList<>();
        List<UserVO> msgList = new ArrayList<>();

        for (int i = 1; i < excelList.size(); i++) {
            String number = excelList.get(i).get(0);
            if (!StringUtils.isEmpty(number)) {
                UserVO userVO = new UserVO();
                userVO = this.validateExcel(excelList.get(i), i);
                if (Validator.isNull(userVO) && Validator.isNotNull(userVO.getMsg()) && !"".equals(userVO.getMsg())) {
                    msgList.add(userVO);
                } else {
                    userVO = this.importdetail(excelList.get(i), userVO);
                    //角色未找到或者组织机构未找到
                    if (!StringUtils.isBlank(userVO.getMsg())) {
                        UserVO userVO1 = new UserVO();
                        userVO1.setMsg(userVO.getMsg());
                        msgList.add(userVO1);
                    } else {
                        dtoList.add(userVO);
                    }
                }
            }
            if (Validator.isEmpty(msgList) || msgList.size() == 0) {
                if (Validator.isNotEmpty(dtoList) && dtoList.size() != 0) {
                    dtoList.forEach(user -> {
                        user.setPassword(SecureUtil.md5("123456"));
                        userDao.insert(user);

                        processUserRole(user, user.getRoleVOS());
                    });
                } else {
                    UserVO userVO = new UserVO();
                    userVO.setMsg(ExcelConstants.FACLITY_DATA_IMPORT.EXCEL_IS_NULL);
                    msgList.add(userVO);
                }
            }

        }
        return msgList;
    }


    public UserVO importdetail(List<String> excelList, UserVO user) {
        StringBuilder msg = new StringBuilder();
        user.setUsername(DeEnCode.encode(excelList.get(1)));
        user.setTellNumber(DeEnCode.encode(excelList.get(2)));
        user.setTrueName(DeEnCode.encode(excelList.get(3)));

        //找角色
        String[] roleNames = excelList.get(4).split(";");
        if (null == roleNames || "".equals(roleNames)) {
            roleNames[0] = excelList.get(5);
        }
        List<RoleVO> roleVOS = roleService.findByName(roleNames);
        List<RoleVO> roleVOList = roleVOS.parallelStream()
                .filter(roleVO -> null != roleVO.getMsg() && !"".equals(roleVO.getMsg()))
                .collect(Collectors.toList());
        //存在角色未找到
        if (CollectionUtil.isNotEmpty(roleVOList)) {
            roleVOList.forEach(roleVO -> {
                msg.append(roleVO.getMsg());
            });

        } else {
            user.setRoleVOS(roleVOS);
        }

        //找组织机构
        String[] organNames = excelList.get(5).split("-");
        List<String> organNameList = new ArrayList();
        for (int i = 0; i < organNames.length; i++) {
            organNameList.add(organNames[i]);
        }
        OrganVO organ = organService.findOrganByNames(organNameList);
        if (Validator.isNull(organ)) {
            msg.append("该组织机构不存在！");
        } else {
            user.setOrganId(organ.getId());
        }

        user.setLoveName(excelList.get(6));
        user.setEmail(excelList.get(7));
        user.setMsg(msg.toString());
        return user;
    }

    public UserVO validateExcel(List<String> list, int i) {
        UserVO userVO = new UserVO();
        StringBuilder msg = new StringBuilder();
        if (Validator.isNull(list.get(1))) {
            msg.append("第" + (i + 1) + "行，用户名称不允许为空");
        }
        if (Validator.isNull(list.get(2))) {
            msg.append("第" + (i + 1) + "行，联系方式不允许为空");
        }
        User user1 = userDao.findUserByTellOrName(DeEnCode.encode(list.get(1)));
        User user2 = userDao.findUserByTellOrName(DeEnCode.encode(list.get(2)));
        if (Validator.isNotNull(user1) || Validator.isNotNull(user2)) {
            msg.append("第" + (i + 1) + "行，该用户已经存在");
        }
        if (Validator.isNull(list.get(3))) {
            msg.append("第" + (i + 1) + "行，真实姓名不允许为空");
        }
        if (Validator.isNull(list.get(4))) {
            msg.append("第" + (i + 1) + "行，角色名称不允许为空");
        }
        if (Validator.isNull(list.get(5))) {
            msg.append("第" + (i + 1) + "行，组织机构不允许为空");
        }
        String[] organNames = list.get(5).split("-");
        if (null == organNames || "".equals(organNames) || organNames.length <= 3) {
            msg.append("第" + (i + 1) + "行，组织机构没有按照规则填写，应该按照 父级名称-子级-子子级-.... 的格式填写");
        }

        if (Validator.isNotNull(msg)) {
            userVO.setMsg(msg.toString());
        }
        return userVO;
    }

    /**
     *
     * 功能描述: 修改当前登录用户信息
     *
     * @param:
     * @return:
     */
    public UserVO modifyCurrentUser(UserVO userVO){
        if(Validator.isNull(userVO)){
            return null;
        }
        userDao.update(userVO);
        UserVO vo=findDetailUser(userVO.getId());
//        UserVO vo = userDao.searchOne(userVO.getId());
        redisUtil.setex(RedisKey.USER.of(vo.getId().toString()),vo);
        return deCodeUser(vo);
    }

    @Transactional
    public UserVO modify(UserVO userVO) {
        this.validateForModify(userVO);
        UserVO existUser = userDao.searchOne(userVO.getId());
        if (Validator.isNull(existUser)) {
            throw ServiceException.create(UserMsgCode.USER_NOT_EXIST);
        }
        if (!existUser.getOrganId().equals(userVO.getOrganId())) {
            //TODO 更新人员台账中对应的组织机构
        }
        userDao.update(this.enCodeUser(userVO));

        User user = new User();
        BeanUtils.copyProperties(existUser, user);
        processUserRole(user, userVO.getRoleVOS());
        UserVO vo = userDao.searchOne(userVO.getId());
        //如果修改的为当前登录用户，刷新缓存
        if(vo.getId()==currentUser().getId()){
            redisUtil.setex(RedisKey.USER.of(user.getId().toString()),userVO);
        }
        return this.deCodeUser(vo);

    }

    public void validateForModify(UserVO userVO) {
        if (Validator.isNotNull(userVO)) {
            User user1 = userDao.findUserByTellOrName(DeEnCode.encode(userVO.getUsername()));
            User user2 = userDao.findUserByTellOrName(DeEnCode.encode(userVO.getTellNumber()));
            if (Validator.isNotNull(user1) || Validator.isNotNull(user2)) {
                if (!user1.getId().equals(userVO.getId()) || !user2.getId().equals(userVO.getId())) {
                    throw ServiceException.create(UserMsgCode.USER_ALL_EXIST);
                }
            }
        }

    }

    public void delete(Long userId) {
        userRoleDao.deleteByUserId(userId);
        userDao.delete(userId);
    }

    /**
     * 功能描述: 重置密码
     *
     * @param:
     * @return:
     */
    public void restPassword(PasswordVO passwordVO) {
        this.validatePassword(passwordVO.getNewPassword());
        this.validatePassword(passwordVO.getOldPassword());

        Long userId = currentUser().getId();
        UserVO user = this.validatePassword(passwordVO, userId);
        if (passwordVO.getNewPassword().equals(passwordVO.getOldPassword())) {
            throw ServiceException.create(UserMsgCode.USER_PASSWORD_IS_THE_SAME);
        }
        user.setPassword(DeEnCode.encode(passwordVO.getNewPassword()));
        user.setLoginNum(currentUser().getLoginNum());
        userDao.update(user);

    }

    public UserVO validatePassword(PasswordVO passwordVO, Long userId) {
        UserVO user = userDao.searchOne(userId);
        if (Validator.isNull(user)) {
            throw ServiceException.create(UserMsgCode.USER_NOT_EXIST);

        }
        if (!DeEnCode.encode(passwordVO.getOldPassword()).equalsIgnoreCase(user.getPassword())) {
            throw ServiceException.create(LoginMsgCode.USER_PASSWORD_ERROR);
        }
        return user;
    }

    public void validatePassword(String password) {
        if (StringUtils.isEmpty(password)) {
            log.warn("Password cannot be null.");
            throw ServiceException.create(UserMsgCode.USER_PASSWORD_IS_NULL);
        }
        if (!Validator.isGeneral(password, 5, 100)) {
            log.warn("Password cannot be null.");
            throw ServiceException.create(UserMsgCode.USER_PASSWORD_NOT_VALID);
        }
    }

    public Set<Long> getUserRoleIds() {
        UserVO userVo = this.currentUser();
        return this.getUserRoleIds(userVo);
    }

    private Set<Long> getUserRoleIds(UserVO userVo) {
        Set<Long> roleIds = Collections.emptySet();
        if (Validator.isNotEmpty(userVo.getRoleVOS())) {
            roleIds = userVo.getRoleVOS().parallelStream().map(RoleVO::getId).collect(Collectors.toSet());
        } else {
            throw ServiceException.create(UserMsgCode.USER_NO_ROLE_FOUND);
        }
        return roleIds;
    }

    public List<PrivilegeVO> getPrivilegeTree() {
        UserVO userVo = this.findDetailUser(currentUser().getId());
        return privilegeService.getPrivilegeTree(userVo);
    }

    public void validateMobileNo(String mobileNo) {
        if (Validator.isEmpty(mobileNo)) {
            throw ServiceException.create(UserMsgCode.USER_MOBILE_NO_IS_NULL);
        }
        if (!Validator.isMobile(mobileNo)) {
            throw ServiceException.create(UserMsgCode.USER_MOBILE_NO_NOT_VALID);
        }
    }

    public User findUserByTell(String tell) {
        User user = userDao.findByTell(tell);
        return user;
    }


    //加密 用户名 真名 电话号码
    public UserVO enCodeUser(UserVO userVO) {
        UserVO vo = new UserVO();
        BeanUtils.copyProperties(userVO, vo);
        vo.setUsername(DeEnCode.encode(userVO.getUsername()));
        vo.setTrueName(DeEnCode.encode(userVO.getTrueName()));
        vo.setTellNumber(DeEnCode.encode(userVO.getTellNumber()));
        return vo;
    }

    //解密 用户名 真名 电话号码
    public UserVO deCodeUser(UserVO userVO) {
        UserVO vo = new UserVO();
        BeanUtils.copyProperties(userVO, vo);
        vo.setUsername(DeEnCode.decode(userVO.getUsername()));
        vo.setTrueName(DeEnCode.decode(userVO.getTrueName()));
        vo.setTellNumber(DeEnCode.decode(userVO.getTellNumber()));
        return vo;
    }


}
